﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Attributes
{
    public class TaxIdValidAttribute : ValidationAttribute
    {
        bool ValidTaxId(string valueString)
        {
            if (valueString.Length < 12)
                return ValidCpf(valueString);
            else
                return ValidCnpj(valueString);
        }
        bool ValidCpf(string valueCpf)
        {
            Int64 n = 0;
            if (!Int64.TryParse(valueCpf, out n))
            {
                if (string.IsNullOrEmpty(valueCpf) || (valueCpf.Length > 0 && !valueCpf.Substring(0, 1).Equals("E")))
                    return false;
                return true;
            }

            string valor = valueCpf.Replace(".", "").Replace("-", "");

            valor = Convert.ToInt64(valor).ToString().PadLeft(11, '0');

            if (valor.Length != 11)
                return false;

            bool igual = true;

            for (int i = 1; i < 11 && igual; i++)
                if (valor[i] != valor[0])
                    igual = false;

            if (igual || valor == "12345678909")
                return false;

            int[] numeros = new int[11];

            for (int i = 0; i < 11; i++)
                numeros[i] = int.Parse(valor[i].ToString());

            int soma = 0;

            for (int i = 0; i < 9; i++)
                soma += (10 - i) * numeros[i];

            int resultado = soma % 11;

            if (resultado == 1 || resultado == 0)
            {
                if (numeros[9] != 0)
                    return false;
            }
            else if (numeros[9] != 11 - resultado)
                return false;

            soma = 0;

            for (int i = 0; i < 10; i++)
                soma += (11 - i) * numeros[i];

            resultado = soma % 11;

            if (resultado == 1 || resultado == 0)
            {
                if (numeros[10] != 0)
                    return false;
            }
            else
                if (numeros[10] != 11 - resultado)
                    return false;

            return true;
        }
        bool ValidCnpj(string valueCnpj)
        {
            string cnpj = valueCnpj.Replace(".", "").Replace("/", "").Replace("-", "");

            Int64 n = 0;
            if (!Int64.TryParse(cnpj, out n))
            {
                if (string.IsNullOrEmpty(cnpj) || (cnpj.Length > 0 && !cnpj.Substring(0, 1).Equals("E")))
                    return false;
                return true;
            }

            cnpj = Convert.ToInt64(cnpj).ToString().PadLeft(14, '0');

            int[] digitos, soma, resultado;
            int nrdig;
            string ftmt;
            bool[] cnpjok;

            ftmt = "6543298765432";
            digitos = new int[14];
            soma = new int[2];
            soma[0] = 0;
            soma[1] = 0;
            resultado = new int[2];
            resultado[0] = 0;
            resultado[1] = 0;
            cnpjok = new bool[2];
            cnpjok[0] = false;
            cnpjok[1] = false;

            try
            {
                for (nrdig = 0; nrdig < 14; nrdig++)
                {
                    digitos[nrdig] = int.Parse(cnpj.Substring(nrdig, 1));
                    if (nrdig <= 11)
                        soma[0] += (digitos[nrdig] * int.Parse(ftmt.Substring(nrdig + 1, 1)));
                    if (nrdig <= 12)
                        soma[1] += (digitos[nrdig] * int.Parse(ftmt.Substring(nrdig, 1)));
                }

                for (nrdig = 0; nrdig < 2; nrdig++)
                {
                    resultado[nrdig] = (soma[nrdig] % 11);
                    if ((resultado[nrdig] == 0) || (resultado[nrdig] == 1))
                        cnpjok[nrdig] = (digitos[12 + nrdig] == 0);
                    else
                        cnpjok[nrdig] = (digitos[12 + nrdig] == (11 - resultado[nrdig]));
                }
                return (cnpjok[0] && cnpjok[1]);
            }
            catch
            {
                return false;
            }
        }

        public override bool IsValid(object value)
        {
            var taxId = value == null ? string.Empty : value.ToString().Replace(".", "").Replace("/", "").Replace("-", "");

            if (string.IsNullOrEmpty(taxId))
                return true;

            bool valid = ValidTaxId(taxId);

            if (!valid)
                ErrorMessage = taxId.Length < 12 ? "CPF inválido" : "CNPJ inválido";

            return valid;
        }
    }
}
